home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / lib / dial / d_script.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-02-28  |  26.3 KB  |  1,137 lines

  1. # include  "util.h"
  2. # include  <signal.h>
  3. # include  "d_syscodes.h"
  4. # include  "d_proto.h"
  5. # include  "d_returns.h"
  6. # include  <stdio.h>
  7. #if defined(SYS5) || defined(M_XENIX)
  8. # include  <string.h>
  9. #else
  10. # include  <strings.h>
  11. #endif
  12. # include  "d_structs.h"
  13. # include  "d_script.h"
  14.  
  15. /*  Jun 81  D. Crocker    rgetc() tossed out almost all the control
  16.  *                        characters.  changed to toss only null & DEL
  17.  *  Sep 83  G.B. Reilly   added support for script command for prompt
  18.  *          M. Laubach    recognition.
  19.  */
  20.  
  21. extern char *dupfpath();
  22. extern char *tbldfldir;
  23. extern int errno;
  24. extern FILE *d_scfp;
  25. extern  unsigned short d_lxill[],
  26.                d_lrill[];
  27. extern int d_baudrate;
  28. extern int d_errno;
  29. extern int d_lxmax;
  30. extern int d_lrmax;
  31. extern int d_debug;
  32. extern int d_xretry;
  33. extern int d_toack;
  34. extern int d_todata;
  35. extern int d_wpack;
  36. #ifdef SYS5
  37. extern unsigned short d_prbitc, d_prbiti, d_prbito, d_prbitl;
  38. extern unsigned short d_scbitc, d_scbiti, d_scbito, d_scbitl;
  39. #else
  40. extern int d_pron, d_proff, d_scon, d_scoff;
  41. #endif /* SYS5 */
  42. extern int d_nbuff;
  43. extern int d_didial;
  44. extern  FILE * d_prtfp;
  45. /*** prompt varibable ******************** reilly@udel-relay     ***/
  46. int d_prompt = 0;         /* global prompt var.  =0 means disabled */
  47.                           /* <>0 is ascii value of prompt character*/
  48.  
  49. #define MAXNUMS 5
  50. #define NOPARSE -1
  51. #define IGNORE -2
  52. #define ANYARGS -3
  53.  
  54. /*  structure defining the legal script file commands, their type,
  55.  *  and legal number of fields.
  56. */
  57. struct scrcmds
  58. {
  59.     char   *s_cmdname;          /*  command string  */
  60.     int     s_cmdtype;          /*  command type number  */
  61.     int     s_cmdminfields;      /*  min number of fields for command  */
  62.     int     s_cmdmaxfields;       /*  max number of fields allowed */
  63. }               d_sccmds[] =
  64. {
  65.                     "dial", S_DIAL, 2, 2,
  66.                     "conn", S_DIAL, 2, 2,
  67.                     "phone", S_DIAL, 2, 2,
  68.                     "xillegal", S_XILL, 2, 2,
  69.                     "rillegal", S_RILL, 2, 2,
  70.                     "xmitill", S_XILL, 2, 2,
  71.                     "recvill", S_RILL, 2, 2,
  72.                     "xmitpack", S_XPCK, 2, 2,
  73.                     "recvpack", S_RPCK, 2, 2,
  74.                     "xmitsize", S_XPCK, 2, 2,
  75.                     "recvsize", S_RPCK, 2, 2,
  76.                     "transmit", S_XMIT, 2, 2,
  77.                     "send", S_XMIT, 2, 2,
  78.                     "xmit", S_XMIT, 2, 2,
  79.                     "receive", S_RECV, 3, 3,
  80.                     "recv", S_RECV, 3, 3,
  81.                     "start", S_GO, 1, 1,
  82.                     "go", S_GO, 1, 1,
  83.                     "end", S_END, 1, 1,
  84.                     "stop", S_END, 1, 1,
  85.                     "bye", S_END, 1, 1,
  86.                     "nrexmit", S_RETR, 2, 2,
  87.                     "waitack", S_TOAK, 2, 2,
  88.                     "waitdata", S_TODA, 2, 2,
  89.             "{", S_SELST, 1, 1,
  90.             "}", S_SELEND, 1, 1,
  91.             "alternate", S_ALT, 1, 1,
  92.             "case", S_ALT, 1, 1,
  93.             "cmnt", S_REM, IGNORE, IGNORE,
  94.             "rem", S_REM, IGNORE, IGNORE, 
  95.             "rem:", S_REM, IGNORE, IGNORE, 
  96.             "com", S_REM, IGNORE, IGNORE, 
  97.             "com:", S_REM, IGNORE, IGNORE,
  98.             "#", S_REM, IGNORE, IGNORE,
  99.             "log", S_LOG, 2, 2,
  100.             "abort", S_ABORT, 1, 1,
  101.             "bill", S_BILL, 3, 3,
  102.             "replay", S_REPLAY, 1, 1,
  103.             "mark", S_MARK, 1, 1,
  104. #ifdef SYS5
  105.             "stty-pr", S_PRTTY, 3, 5,
  106.             "stty-sc", S_SCTTY, 3, 5,
  107. #else
  108.             "stty-pr", S_PRTTY, 3, 3,
  109.             "stty-sc", S_SCTTY, 3, 3,
  110. #endif /* SYS5 */
  111.             "window", S_DBLBUF, 3, 3,
  112.             "use", S_USEFILE, 2, ANYARGS,
  113. /*** prompt command has one format  "prompt <val>"      reilly@udel-relay ***/
  114.             "prompt", S_PROMPT, 2, 2,
  115.                     0, 0, 0, 0,
  116. };
  117.  
  118. char    d_scfile[82],            /*  script file path name  */
  119.         d_rawq[MATCHLEN],      /*  pushback queue for string matcher  */
  120.        *d_prawq;                  /*  pointer to next available character */
  121.                   /*  in 'd_rawq'.  */
  122.  
  123. unsigned d_scline;                /*  current line number in script file  */
  124. int     d_nfields = 0;          /*  current number of "use" fields */
  125. char    *d_fields[MAXFIELDS];     /*  current "use" fields */
  126.  
  127. int     d_ntries = 2,             /*  number of times to try to dial numbers
  128.                   */
  129.     d_wait = 15,              /*  number of seconds to wait between dial
  130.                   */
  131.                   /*  attempts.                               
  132.                   */
  133.         d_nrawq;          /*  number of available characters in
  134.                      'd_rawq'  */
  135. int    d_dodrop;          /*  non zero if a dial has been made  */
  136.  
  137. LOCVAR int d_gotxill = 0;      /* non zero if xill command received */
  138. LOCVAR int d_gotrill = 0;      /* non zero if rill command received */
  139.  
  140. /*
  141.  *     D_SCRIPT
  142.  *
  143.  *     this routine reads lines from the script file, parses them up, and
  144.  *     then initiates the requested actions.
  145.  */
  146.  
  147. d_script ()
  148.     {
  149.     register int nselect, result;
  150.     char linebuf[MAXSCRLINE + 2],
  151.      *fields[MAXFIELDS];
  152.     int nfields;
  153.  
  154.     nselect = 0;
  155.     d_dodrop = 0;
  156.  
  157.     for (;;)
  158.     {
  159.     result = d_scrblk ();
  160.  
  161.     switch (result)
  162.     {
  163.         case D_OK:
  164.         return(D_OK);
  165.  
  166.         case D_FATAL:
  167.         case D_EOF:
  168.         case D_NFIELDS:
  169.         case D_QUOTE:
  170.         case D_UNKNOWN:
  171.         return (D_FATAL);
  172.  
  173.         case D_NONFATAL:
  174.         /*  An error that may be recoverable.  If there is
  175.          *  an alternate, use it.
  176.          */
  177.         if (nselect <= 0)
  178.             /*  Not within a select block; therefore, not alt  */
  179.             return (D_FATAL);
  180.  
  181.         /*  We are within a select block;  go to the alternate  */
  182.         if ((result = d_nxtalt ()) < 0)
  183.             return (result);
  184.         switch (result)
  185.         {
  186.             case S_ALT:
  187.             continue;
  188.  
  189.             case S_SELEND:
  190.             /*  no more alternates;  return error  */
  191.             return (D_FATAL);
  192.  
  193.             default:
  194.             d_scerr ("Bad syntax scriptfile");
  195.             return (D_FATAL);
  196.         }
  197.  
  198.  
  199.         case S_SELST:
  200.         /*  The next line had better be an alternate  */
  201.         if (d_cmdget (linebuf, &nfields, fields, d_scfp) != S_ALT)
  202.         {
  203.             d_scerr ("Missing 'alternate' after 'begin'");
  204.             return (D_FATAL);
  205.         }
  206.         nselect++;
  207.         continue;
  208.  
  209.         case S_SELEND:
  210.         /*  verify that there was a select block being
  211.          *  looked at.  If so, then the last alternate
  212.          *  was the successful one.  Continue normally.
  213.          */
  214.         if (nselect-- <= 0)
  215.         {
  216.             d_scerr ("Inappropriate select end");
  217.             return (D_FATAL);
  218.         }
  219.         continue;
  220.  
  221.         case S_ALT:
  222.         /*  First, make sure the context was correct  */
  223.         if (nselect <= 0)
  224.         {
  225.             d_scerr ("Inappropriate alt\n");
  226.             return (D_FATAL);
  227.         }
  228.         /*  If we get here, then an alternate within a select
  229.          *  was completed successfully.  Move on.
  230.          */
  231.         if ((result = d_selend ()) < 0)
  232.             return (result);
  233.         nselect--;
  234.         switch (result)
  235.         {
  236.             case S_SELEND:
  237.             continue;
  238.  
  239.             default:
  240.             d_scerr ("error in format of script file");
  241.             return (D_FATAL);
  242.         }
  243.  
  244.         default:
  245.         if (result < 0)
  246.             return (result);
  247.         d_scerr ("d_script", "Internal error: result = %d", result);
  248.         return (D_FATAL);
  249.     }
  250.  
  251.     }
  252. }
  253.  
  254. d_scrblk ()
  255.     {
  256.     char linebuf[MAXSCRLINE + 2],
  257.          *fields[MAXFIELDS];
  258.     int command, result, nfields;
  259.  
  260.     for (;;)
  261.     {
  262.     /*  read the command  */
  263.     command = d_cmdget (linebuf, &nfields, fields, d_scfp);
  264.     if (command < 0)
  265.         return (command);
  266.  
  267.  
  268.     result = d_cmdproc(command, nfields, fields);
  269.     if (result == D_CONTIN)
  270.         continue;
  271.     return (result);
  272.     }
  273. }
  274.  
  275. d_cmdproc (command, nfields, fields)
  276.   int command, nfields;
  277.   char *fields[];
  278.     {
  279.     register int result, word, i;
  280.     register char *ptr;
  281.  
  282.     /*  switch out on the command type.  for most of the commands,
  283.      *  there is a routine to handle them.
  284.      */
  285.     switch (command)
  286.     {
  287.     case S_EOF:
  288.         /*  Not really a script command.  This is returned to
  289.          *  indicate an unexpected EOF on the script input file.
  290.          *  Try to revert to a previous script file.  If there is
  291.          *  none, then this really is an unexpected EOF.  Return
  292.          *  an error to indicate so.
  293.          */
  294.         if (d_scclose() > 0)
  295.         return (D_CONTIN);
  296.         return (D_EOF);
  297.  
  298.     case S_DBLBUF:
  299.         /*  Can use 'd_nbuff' as a counter of the number of
  300.          *  outstanding packets to allow if we later mod the
  301.          *  code to allow more than double buffering.
  302.          *  See the file 'd_packet.c'
  303.          */
  304.         result = atoi (fields[1]);
  305. #ifdef D_LOG
  306.         if ((result != 1) &&
  307.         (result != 2)   )
  308.         d_log("d_cmdproc", "Illegal buffer number, %d", result);
  309.         else
  310. #endif /* D_LOG */
  311.         d_nbuff = result;
  312.  
  313.         /*  This variable will be non-zero if the master startup
  314.          *  routine should transmit a packet telling the other
  315.          *  side about the buffering window.  This packet can not
  316.          *  be transmitted to sites running the old code.
  317.          */
  318.         d_wpack = atoi (fields[2]);
  319.         return (D_CONTIN);
  320.  
  321.     case S_USEFILE:
  322.         /*  takes additional input from another file until
  323.          *  that file is exhausted.
  324.          */
  325.  
  326.         fields[1] = dupfpath(fields[1], tbldfldir);    
  327.  
  328.         for (i = 2; i <= nfields; i ++)
  329.         {
  330.         if (*fields[i] == '"') fields[i]++;
  331.         if (ptr = rindex(fields[i], '"')) *ptr = '\0';
  332.         }
  333.  
  334.         if (d_scopen (fields[1], nfields, &fields[0]) < 0)
  335.         return (D_FATAL);
  336.         return (D_CONTIN);
  337.  
  338.     case S_PRTTY:
  339. #ifdef SYS5
  340.         sscanf(fields[1], "%ho", &d_prbitc);
  341.         sscanf(fields[2], "%ho", &d_prbiti);
  342.         sscanf(fields[3], "%ho", &d_prbito);
  343.         sscanf(fields[4], "%ho", &d_prbitl);
  344.  
  345. #ifdef D_LOG
  346.         d_log("d_cmdproc", "%s %o %o %o %o", fields[0],
  347.         d_prbitc, d_prbiti, d_prbito, d_prbitl);
  348. #endif /* D_LOG */
  349.  
  350. #else /* SYS5 */
  351.         /*  Could use fields[1&2], but let's check consistancy  */
  352.         sscanf(fields[1], "%o", &d_pron);
  353.         sscanf(fields[2], "%o", &d_proff);
  354. #ifdef D_LOG
  355.         d_log("d_cmdproc", "%s %o %o", fields[0], d_pron, d_proff);
  356. #endif /* D_LOG */
  357. #endif /* SYS5 */
  358.         return (D_CONTIN);
  359.  
  360.     case S_SCTTY:
  361. #ifdef SYS5
  362.         sscanf(fields[1], "%ho", &d_scbitc);
  363.         sscanf(fields[2], "%ho", &d_scbiti);
  364.         sscanf(fields[3], "%ho", &d_scbito);
  365.         sscanf(fields[4], "%ho", &d_scbitl);
  366.  
  367. #ifdef D_LOG
  368.         d_log("d_cmdproc", "%s %o %o %o %o", fields[0],
  369.         d_scbitc, d_scbiti, d_scbito, d_scbitl);
  370. #endif /* D_LOG */
  371.  
  372. #else
  373.  
  374.         sscanf(fields[1], "%o", &d_scon);
  375.         sscanf(fields[2], "%o", &d_scoff);
  376. #ifdef D_LOG
  377.         d_log("d_cmdproc", "%s %o %o", fields[0], d_scon, d_scoff);
  378. #endif /* D_LOG */
  379. #endif /* SYS5 */
  380.         return (D_CONTIN);
  381.  
  382.     case S_MARK:
  383.         d_mark ();
  384.         return (D_CONTIN);
  385.  
  386.     case S_REPLAY:
  387.         d_replay ();
  388.         return (D_CONTIN);
  389.  
  390.     case S_LOG:
  391.         /*  Force this to always log  */
  392.         d_plog (-1, "%s", fields[1]);
  393.         return (D_CONTIN);
  394.  
  395.     case S_BILL:
  396.         d_didial = 1;  /* pretend we're dialport for dial_log purposes */
  397.         d_cstart(fields[1], fields[2]);
  398.         return (D_CONTIN);
  399.  
  400.     case S_REM:
  401.         return (D_CONTIN);
  402.  
  403.     case S_ABORT:
  404.         return (D_FATAL);
  405.  
  406.     case S_ALT:
  407.     case S_SELST:
  408.     case S_SELEND:
  409.         return (command);
  410.  
  411.     case S_DIAL:        /* get line & make raw mode for matching */
  412.         /*  Make sure any previous connections are cleaned up  */
  413.         if (d_dodrop != 0)
  414.         {
  415.         d_dodrop = 0;
  416.         d_drop ();
  417.         }
  418.  
  419.         /*  Don't let input from last dial get in this one's queue  */
  420.         d_mark ();
  421.  
  422.         if (d_scdial (fields[1]) < 0)
  423.         return (D_NONFATAL);
  424.         d_dodrop = 1;
  425.         return (D_CONTIN);
  426.  
  427.     case S_XMIT: 
  428.         if ((result = d_scxmit (fields[1])) < 0)
  429.         return (result);
  430.         return (D_CONTIN);
  431.  
  432.     case S_RECV: 
  433.         if ((result = d_screcv (fields[1], fields[2])) < 0)
  434.             return (result);
  435.         return (D_CONTIN);
  436.  
  437.     case S_GO:          /* regular tty mode during session */
  438. /*** expanded to call and log ttscript when prompt active ***/
  439. /*** necessary to get raw mode for control chars          ***/
  440. /*** 9/27/83   laubach@udel-relay                         ***/
  441.         if (d_prompt == 0) {
  442.                 if (d_ttproto (d_baudrate) < 0)
  443.         return (D_NONFATAL);
  444.             } 
  445.             else {
  446.                 if (d_ttscript ( d_baudrate) < 0)
  447.                 return (D_NONFATAL);
  448. #ifdef D_DBGLOG
  449.                 d_dbglog("d_cmdproc","ttscript selected for raw prompt mode");
  450. #endif /* D_DBGLOG */
  451.             }
  452.         return (D_OK);
  453.  
  454.     case S_END: 
  455.         return (D_OK);
  456.  
  457.     case S_XPCK: 
  458.         result = atoi (fields[1]);
  459.  
  460.         if ((result < MINPATHSIZ) || (result > MAXPACKET))
  461.         {
  462.         d_scerr ("illegal max transmit packet length: %d", result);
  463.         d_errno = D_SCRERR;
  464.         return (D_NONFATAL);
  465.         }
  466.  
  467. #ifdef D_DBGLOG
  468.         d_dbglog ("d_script", "setting 'd_lxmax' to %d", result);
  469. #endif /* D_DBGLOG */
  470.         d_lxmax = result;
  471.         return (D_CONTIN);
  472.  
  473.     case S_RPCK: 
  474.         result = atoi (fields[1]);
  475.  
  476.             if ((result < MINPATHSIZ) || (result > MAXPACKET))
  477.         {
  478.         d_scerr ("illegal max receive packet length");
  479.         d_errno = D_SCRERR;
  480.         return (D_NONFATAL);
  481.         }
  482.  
  483. #ifdef D_DBGLOG
  484.         d_dbglog ("d_script", "setting 'd_lrmax' to %d", result);
  485. #endif /* D_DBGLOG */
  486.         d_lrmax = result;
  487.         return (D_CONTIN);
  488.  
  489.     case S_XILL: 
  490.         if (!d_gotxill)  { /* zero the vector on first S_XILL command */
  491.         d_gotxill = 1;
  492. #ifdef D_DBGLOG
  493.         d_dbglog("d_script", "zeroing xill vector");
  494. #endif /* D_DBGLOG */
  495.         for (word = 0; word < 8; word++)
  496.             d_lxill[word] = 0;
  497.         }
  498.  
  499.         if ((result = d_scill (fields[1], d_lxill)) < 0)
  500.         return (result);
  501.  
  502. #ifdef D_DBGLOG
  503.         d_dbglog ("d_script", "d_lxill = %o %o %o %o %o %o %o %o",
  504.             d_lxill[0], d_lxill[1], d_lxill[2], d_lxill[3],
  505.             d_lxill[4], d_lxill[5], d_lxill[6], d_lxill[7]);
  506. #endif /* D_DBGLOG */
  507.         return (D_CONTIN);
  508.  
  509.     case S_RILL: 
  510.         if (!d_gotrill)  { /* zero the vector on first S_RILL command */
  511.         d_gotrill = 1;
  512. #ifdef D_DBGLOG
  513.         d_dbglog("d_script", "zeroing rill vector");
  514. #endif /* D_DBGLOG */
  515.         for (word = 0; word < 8; word++)
  516.             d_lrill[word] = 0;
  517.         }
  518.  
  519.         if ((result = d_scill (fields[1], d_lrill)) < 0)
  520.         return (result);
  521.  
  522. #ifdef D_DBGLOG
  523.         d_dbglog ("d_script", "d_lrill = %o %o %o %o %o %o %o %o",
  524.             d_lrill[0], d_lrill[1], d_lrill[2], d_lrill[3],
  525.             d_lrill[4], d_lrill[5], d_lrill[6], d_lrill[7]);
  526. #endif /* D_DBGLOG */
  527.         return (D_CONTIN);
  528.  
  529.     case S_RETR:
  530.         result = atoi (fields[1]);
  531.         if (result <= 0)
  532.         d_scerr("d_script", "Bad retry value: %d", result);
  533.         else
  534.         d_xretry = result;
  535.         return (D_CONTIN);
  536.  
  537.     case S_TOAK:
  538.         result = atoi (fields[1]);
  539.         if (result <= 0)
  540.         d_scerr ("d_script", "Bad ack time out value: %d", result);
  541.         else
  542.         d_toack = result;
  543.         return (D_CONTIN);
  544.  
  545.     case S_TODA:
  546.         result = atoi (fields[1]);
  547.         if (result <= 0)
  548.         d_scerr ("d_script", "Bad data time out value: %d", result);
  549.         else
  550.         d_todata = result;
  551.         return (D_CONTIN);
  552.  
  553. /*** prompt has one field which is the decimal ascii value of the prompt ***/
  554. /*** character                                        reilly@udel-relay  ***/
  555.     case S_PROMPT:
  556.         d_prompt = atoi (fields[1]);
  557. #ifdef D_DBGLOG
  558.         d_dbglog ("d_script", "Prompt ASCII %d (decimal)", d_prompt);
  559. #endif /* D_DBGLOG */
  560.         return (D_CONTIN);
  561.  
  562.     default: 
  563.         d_scerr ("internal error -- unknown command %d", command);
  564.         return (D_FATAL);
  565.     }
  566. }
  567.  
  568. d_cmdget (linebuf, nfields, fields, channel)
  569.   int *nfields;
  570.   char *linebuf, *fields[];
  571.   FILE *channel;
  572.     {
  573.     register int result;
  574.     char *nstart;
  575.     int command, nwantmin, nwantmax;
  576.     register struct scrcmds *cmdpt;
  577.    
  578.     /*  read a line from the script file  */
  579. again:
  580.     if ((result = d_scgetline (linebuf, channel)) < 0)
  581.     return (result);
  582.  
  583.     if (result == 0)
  584.     return (S_EOF);
  585.  
  586. #ifdef D_DBGLOG
  587.     d_dbglog ("d_scrproc", "line %d - '%s'", d_scline, linebuf);
  588. #endif /* D_DBGLOG */
  589.  
  590.     /*  First, seperate off the first field of the input line  */
  591.     switch (d_getword(linebuf, &fields[0], &nstart))
  592.     {
  593.     case -1:
  594.         /*  end of line.  I.e, no line.  Try again  */
  595.         goto again;
  596.  
  597.     case -2:
  598.         /*  unterminated quote.  */
  599.         d_scerr ("quoted string missing end quote");
  600.         return (D_QUOTE);
  601.  
  602.     case 0:
  603.         /*  Found a word OK  */
  604.         break;
  605.  
  606.     default:
  607.         d_scerr ("unknown return from d_getword");
  608.         return (D_FATAL);
  609.     }
  610.  
  611.     /*  search the command list for the string in the first field
  612.      *  of the line.
  613.      */
  614.     cmdpt = d_sccmds;
  615.     for(;;)
  616.     {
  617.     if (cmdpt -> s_cmdname == 0)
  618.     {
  619.         d_scerr ("command not known");
  620.         return (D_UNKNOWN);
  621.     }
  622.  
  623.     if (strcmp (fields[0], cmdpt -> s_cmdname) != 0)
  624.     {
  625.         cmdpt++;
  626.         continue;
  627.     }
  628.  
  629.     command = cmdpt -> s_cmdtype;
  630.     nwantmin = cmdpt -> s_cmdminfields;
  631.     nwantmax = cmdpt -> s_cmdmaxfields;
  632.     break;
  633.     }
  634.  
  635.     /*  if this is meant to be tossed, go get another line */
  636.     if (nwantmin == IGNORE)
  637.     goto again;  
  638.  
  639.     /*  if this is not meant to be parsed further, don't  */
  640.     if (nwantmin == NOPARSE)
  641.     {
  642.     fields[1] = nstart;
  643.     return (command);
  644.     }
  645.  
  646.     /*  parse the rest of the line and make sure the right number
  647.      *  of fields are present.
  648.      */
  649.     *nfields = d_linparse (&fields[1], nstart, MAXFIELDS-1);
  650.     if (*nfields < 0)
  651.         switch (*nfields)
  652.     {
  653.         case -1: 
  654.         d_scerr ("too many fields");
  655.         return (D_NFIELDS);
  656.  
  657.         case -2: 
  658.         d_scerr ("quoted string missing end quote");
  659.         return (D_QUOTE);
  660.  
  661.         case -3: 
  662.         d_scerr ("backquote appeared at end of line");
  663.         return (D_QUOTE);
  664.  
  665.         case -4:
  666.         d_scerr ("invalid $ variable used");
  667.         return (D_FATAL);
  668.  
  669.         case -5:
  670.         d_scerr ("line too long");
  671.         return (D_FATAL);
  672.     
  673.         default: 
  674.         d_scerr ("unknown error from line parser");
  675.             return (D_FATAL);
  676.     }
  677.  
  678.     if ( (nwantmin == ANYARGS || *nfields >= (nwantmin - 1)) &&
  679.          (nwantmax == ANYARGS || *nfields <= (nwantmax - 1)) )
  680.     return (command);
  681.  
  682.     /*  If it gets here, then this command had wrong # of fields  */
  683.     d_scerr ("command has %d fields", (*nfields+1));
  684.     return (D_NFIELDS);
  685. }
  686.  
  687.  
  688.  
  689.  
  690. d_selend ()
  691.     {
  692.     register int command;
  693.     char linebuf[MAXSCRLINE + 2],
  694.      *fields[MAXFIELDS];
  695.     int nfields;
  696.  
  697.     for (;;)
  698.     {
  699.     command = d_cmdget (linebuf, &nfields, fields, d_scfp);
  700.     if (command < 0)
  701.         return (command);
  702.     switch (command)
  703.     {
  704.         default:
  705.         continue;
  706.  
  707.         case S_SELEND:
  708.         return (S_SELEND);
  709.  
  710.         case S_SELST:
  711.         d_selend ();
  712.         continue;
  713.  
  714.     }
  715.     }
  716. }
  717.  
  718. d_nxtalt ()
  719.     {
  720.     register int command;
  721.     char linebuf[MAXSCRLINE + 2],
  722.      *fields[MAXFIELDS];
  723.     int nfields;
  724.  
  725.     for (;;)
  726.     {
  727.     command = d_cmdget (linebuf, &nfields, fields, d_scfp);
  728.     if (command < 0)
  729.         return (command);
  730.     switch (command)
  731.     {
  732.         default:
  733.         continue;
  734.  
  735.         case S_SELEND:
  736.         case S_ALT:
  737.         return (command);
  738.  
  739.         case S_SELST:
  740.         d_selend ();
  741.         continue;
  742.     }
  743.     }
  744. }
  745.  
  746. /*
  747.  *     D_SCRDIAL
  748.  *
  749.  *     this routine is called to do the dial command in the script file.
  750.  *     it just calls lower level routines to parse the number string and
  751.  *     do the actual dialing.
  752.  *
  753.  *     number -- number specification string from the script file
  754.  */
  755.  
  756. d_scdial (number)
  757. register char  *number;
  758. {
  759.     register int    nnumbs,
  760.                     result;
  761.     struct telspeed telnumbs[MAXNUMS];
  762.  
  763. #ifdef D_DBGLOG
  764.     d_dbglog ("d_scdial", "attempting to call '%s'", number);
  765. #endif /* D_DBGLOG */
  766.  
  767. /*  parse the number spec, do the dialing, and set the port to raw mode  */
  768.  
  769.     if ((nnumbs = d_numparse (number, telnumbs, MAXNUMS, d_scfile, d_scline)) < 0)
  770.     return (nnumbs);
  771.  
  772.     if ((result = d_connect (telnumbs, nnumbs, d_ntries, d_wait)) < 0)
  773.     return (result);
  774.  
  775.     return (D_OK);
  776. }
  777.  
  778. /*
  779.  *     D_SCRXMIT
  780.  *
  781.  *     this routine is called to transmit a string given in the script file.
  782.  *     the string is converted to standard internal format and then passed
  783.  *     to a lower transmission routine.
  784.  *
  785.  *     string -- string to be transmitted in 'C' style
  786.  */
  787.  
  788. d_scxmit (string)
  789. register char  *string;
  790. {
  791.     register int    length;
  792.     char    canonstr[MAXSCRLINE];
  793.  
  794.     if (*string == '"')
  795.     if ((length = d_canon (string, canonstr)) < 0)
  796.     {
  797.         d_scerr ("transmit string format error");
  798.         return (D_FATAL);
  799.     }
  800.  
  801.     if (d_xstring (canonstr, length) < 0)
  802.     return (D_FATAL);
  803.  
  804.     return (D_OK);
  805. }
  806.  
  807. /*
  808.  *     D_SCRRECV
  809.  *
  810.  *     this routine is called to wait until a given string is received on
  811.  *     the port.  the routine will return when the sting has been identified.
  812.  *     there is also a timer that is set to cause the routine to return with
  813.  *     an error if the string is not received within the specified interval.
  814.  *
  815.  *     string -- the string to be watched for
  816.  *
  817.  *     timestr -- a timeout value, in seconds, given as an ascii string
  818.  */
  819.  
  820. d_screcv (string, timestr)
  821. char   *string,
  822.        *timestr;
  823. {
  824.     register unsigned int   timeout;
  825.     register int    length,
  826.                     result;
  827.     char    canonstr[MAXSCRLINE];
  828.  
  829. #ifdef D_DBGLOG
  830.     d_dbglog ("d_screcv", "looking for '%s' in '%s' seconds", string, timestr);
  831. #endif /* D_DBGLOG */
  832.  
  833. /*  convert the transmit string, check its length, and convert the timeout  */
  834. /*  value.                                                                  */
  835.  
  836.     if ((length = d_canon (string, canonstr)) < 0)
  837.     {
  838.     d_scerr ("receive string format error");
  839.     return (D_FATAL);
  840.     }
  841.  
  842.     if (length > MATCHLEN)
  843.     {
  844.     d_scerr ("receive string too long");
  845.     return (D_FATAL);
  846.     }
  847.  
  848.     if ((result = atoi (timestr)) < 1)
  849.     {
  850.     d_scerr ("illegal timeout value");
  851.     return (D_FATAL);
  852.     }
  853.     timeout = result;            /* convert to unsigned */
  854.  
  855. /*  set up the timer  */
  856.  
  857.     if (setjmp (timerest)) {
  858.     d_scerr ("no match for '%s' after %d seconds", string, timeout);
  859.     d_errno = D_TIMEOUT;
  860.     return (D_NONFATAL);
  861.     }
  862.     s_alarm ((unsigned) timeout);
  863.  
  864. /*  do the matching  */
  865.  
  866.     while ((result = d_scmatch (canonstr)) == D_NO)
  867.     d_rgetc ();
  868.  
  869.     s_alarm (0);
  870.  
  871.     switch (result)
  872.     {
  873.     case D_OK:
  874.         return (D_OK);
  875.  
  876.     case D_NONFATAL:
  877.         d_scerr ("eof on port while trying match");
  878.         d_errno = D_PORTEOF;
  879.         return (D_NONFATAL);
  880.  
  881.     case D_FATAL:
  882.         d_scerr ("read error on port while trying match");
  883.         d_errno = D_PORTRD;
  884.         return (D_FATAL);
  885.  
  886.     case D_INTRPT:
  887.         d_scerr ("no match for '%s' after %d seconds", string, timeout);
  888.         d_errno = D_TIMEOUT;
  889.         return (D_NONFATAL);
  890.     }
  891.  
  892.     d_errno = D_SYSERR;
  893.     return (D_FATAL);
  894. }
  895.  
  896.  
  897. /*
  898.  *     D_SCILL
  899.  *
  900.  *     this routine is called to translate a string specifying illegal
  901.  *     characters for either transmission or recption, and set the bits
  902.  *     corresponding to those characters in the given bit vector.
  903.  *
  904.  *     string -- pointer to character specification string in canonical
  905.  *               format
  906.  *
  907.  *     bitvector -- pointer to bit vector
  908.  */
  909.  
  910. d_scill (string, bitvector)
  911. char   *string;
  912. unsigned short bitvector[];
  913. {
  914.     register int    bit,
  915.                     length;
  916.     register char  *cp;
  917.     char    canonstr[MAXSCRLINE];
  918.  
  919. /*  translate the character string  */
  920.  
  921.     if ((length = d_canon (string, canonstr)) < 0)
  922.     {
  923.     d_scerr ("error in illegal character specification");
  924.     return (D_FATAL);
  925.     }
  926.  
  927. /*  run through the bytes in the converted string and set the bit  */
  928. /*  corresponding to each one                                      */
  929.  
  930.     cp = canonstr;
  931.  
  932.     for (bit = 0; bit < length; bit++)
  933.     d_setbit (*cp++, bitvector);
  934.  
  935.     return (D_OK);
  936. }
  937.  
  938.  
  939. /*
  940.  *     D_SCMATCH
  941.  *
  942.  *     this routine checks for a match between the string and the input
  943.  *     stream.
  944.  *
  945.  *     string -- string to be matched in the input stream
  946.  *
  947.  *
  948.  *     return values:
  949.  *
  950.  *          D_OK -- the string has been found
  951.  *
  952.  *          D_NO -- the string cannot be matched with the current starting
  953.  *                character.  delete the first character and try again.
  954.  *
  955.  *          D_NONFATAL -- eof on port while reading characters
  956.  *
  957.  *          D_FATAL -- read error on port
  958.  *
  959.  *          D_INTRPT -- no match after the specified time
  960.  */
  961.  
  962. d_scmatch (string)
  963. char   *string;
  964. {
  965.     register int    c,
  966.                     result;
  967.  
  968.     if (*string == '\0')
  969.     return (D_OK);
  970.  
  971.     if ((c = d_rgetc ()) < D_OK)
  972.     return (c);
  973.  
  974.     if (c == *string)
  975.     {
  976.     result = d_scmatch (++string);
  977.  
  978.     if (result < D_OK)
  979.         d_unrgetc (c);
  980.  
  981.     return (result);
  982.     }
  983.     else
  984.     {
  985.     d_unrgetc (c);
  986.     return (D_NO);
  987.     }
  988. }
  989.  
  990. /*
  991.  *     D_RGETC
  992.  *
  993.  *     this routine is used to read characters from the port in raw mode.
  994.  *     to allow matching of strings in the input stream, this function
  995.  *     implements a look behind facility.  the port is read only if the
  996.  *     push back list is empty.
  997.  */
  998.  
  999. d_rgetc ()
  1000. {
  1001.     register int    result;
  1002.     int     theval;
  1003.     char c;
  1004.  
  1005. /*  if the queue isn't empty, use what it has  */
  1006.  
  1007.     if (d_nrawq)
  1008.     {
  1009.     d_nrawq--;
  1010.     return (*d_prawq--);
  1011.     }
  1012.  
  1013. /*  have to read the port.  watch for timeout interrupts  */
  1014.  
  1015.     while ((theval = d_getc (d_prtfp)) != EOF)
  1016.     {
  1017.     c = toascii (theval);    /*  filter out some of the junk characters */
  1018.     if ((result = d_tscribe ((char *) &c, 1)) < 0)
  1019.         return (result);
  1020.  
  1021.     switch (c)
  1022.     {                         /* let controls go by, except         */
  1023.         case '\000':          /* skip null & DEL, because they are  */
  1024.         case '\177':          /* almost always just noise           */
  1025.         continue;
  1026.     }
  1027.  
  1028.     return (c);
  1029.     }
  1030.  
  1031.     if (feof (d_prtfp))
  1032.     return (D_NONFATAL);
  1033.  
  1034.     if (errno == EINTR)
  1035.     return (D_INTRPT);
  1036.  
  1037.     return (D_FATAL);
  1038. }
  1039.  
  1040.  
  1041. /*
  1042.  *     D_UNRGETC
  1043.  *
  1044.  *     this routine pushes back a character onto the look behind queue
  1045.  *     used by the 'd_rgetc' routine
  1046.  *
  1047.  *     c -- the character to be pushed back
  1048.  */
  1049.  
  1050. d_unrgetc (c)
  1051. char    c;
  1052. {
  1053.  
  1054. /*  set up the queue if it isn't ready  */
  1055.  
  1056.     if (d_prawq <= 0)
  1057.     {
  1058.     d_prawq = d_rawq;
  1059.     *d_prawq = c;
  1060.     d_nrawq = 1;
  1061.     return;
  1062.     }
  1063.  
  1064. /*  otherwise, stick it on the end  */
  1065.  
  1066.     *++d_prawq = c;
  1067.     d_nrawq++;
  1068. }
  1069.  
  1070. /*
  1071.  *     D_XSTRING
  1072.  *
  1073.  *     this routine is called to transmit strings on the port.  If the
  1074.  *     string contains octal 377, then the function pauses for 1 second
  1075.  *     before continuing.
  1076.  *
  1077.  *     string -- pointer to string
  1078.  *
  1079.  *     length -- number of characters in string to be sent.
  1080.  */
  1081.  
  1082. d_xstring (string, length)
  1083. register char   *string;
  1084. int     length;
  1085. {
  1086.     register int    result;
  1087.  
  1088. #ifdef D_DBGLOG
  1089.     d_dbglog ("d_xstring", "sending '%s', length %d", string, length);
  1090. #endif /* D_DBGLOG */
  1091.  
  1092.     sleep ((unsigned) 2);       /* permit any needed line-settling      */
  1093.     for ( ; length--; string++)
  1094.     {
  1095.     /* NOSTRICT */
  1096.     if ((int)*string == DELAY_CH)
  1097.         sleep ((unsigned) 1);
  1098.     else if ((int)*string == BREAK_CH)
  1099.         d_brkport();
  1100.     else
  1101.         if ((result = d_wrtport (string, 1)) < 0)
  1102.         break;
  1103.         if (*string == '\r')
  1104.         sleep ((unsigned) 1); /* may nned line-settling   */
  1105.     }
  1106.     sleep ((unsigned) 2);       /* permit any needed line-settling      */
  1107.  
  1108.     return (result);
  1109. }
  1110.  
  1111. /*
  1112.  *     D_SCRERR
  1113.  *
  1114.  *     routine which is called to log errors in the script file.  the
  1115.  *     purpose of this is so the name of the file and the line number
  1116.  *     can be tacked on in one place.
  1117.  *
  1118.  *     format -- 'd_log' type format string
  1119.  *
  1120.  *     a, b, c, d, ... -- variables to be logged
  1121.  */
  1122.  
  1123. /* VARARGS1 */
  1124. d_scerr (format, a, b, c, d, e, f, g, h)
  1125. char   *format;
  1126. unsigned a, b, c, d, e, f, g, h;
  1127. {
  1128. #ifdef D_LOG
  1129.     char    tmpfmt[256];
  1130.  
  1131.     sprintf (tmpfmt, "%s%s", "Error in %s, line %d: ", format);
  1132.  
  1133.     d_log ("d_scerr", tmpfmt, d_scfile, d_scline, a, b, c, d, e, f, g, h);
  1134. #endif /* D_LOG */
  1135.     d_errno = D_SCRERR;
  1136. }
  1137.